package discovery

import (
	"encoding/binary"
	"fmt"
	"math/rand"
	"net"
	"rtps/common"
	"rtps/messages"
	"rtps/transport"
	"time"
)

// SPDP参与者
type Participant struct {
	GUIDPrefix [12]byte
	DomainID   uint32
	Transport  *transport.UDPTransport
	Discovered map[string]*DiscoveredParticipant // key: GUID string
}

// 发现的参与者信息
type DiscoveredParticipant struct {
	GUIDPrefix [12]byte
	Locator    common.Locator
	Timestamp  time.Time
}

// 创建新的SPDP参与者
func NewParticipant(domainID uint32) (*Participant, error) {
	participant := &Participant{
		DomainID:   domainID,
		Discovered: make(map[string]*DiscoveredParticipant),
	}

	// 生成GUID前缀
	rand.Read(participant.GUIDPrefix[:])

	// 创建传输层
	trans, err := transport.NewUDPTransport(common.DefaultPortSPDP)
	if err != nil {
		return nil, fmt.Errorf("failed to create transport: %v", err)
	}
	participant.Transport = trans

	return participant, nil
}

// 启动参与者发现
func (p *Participant) StartDiscovery() error {
	// 启动定期发送SPDP消息的goroutine
	go p.periodicAnnounce()

	// 启动接收SPDP消息的goroutine
	go p.receiveDiscoveryMessages()

	return nil
}

// 定期宣布参与者存在
func (p *Participant) periodicAnnounce() {
	ticker := time.NewTicker(30 * time.Second) // 每30秒发送一次
	defer ticker.Stop()

	for {
		select {
		case <-ticker.C:
			if err := p.sendSPDPMessage(); err != nil {
				fmt.Printf("Failed to send SPDP message: %v\n", err)
			}
		}
	}
}

// 发送SPDP发现消息
func (p *Participant) sendSPDPMessage() error {
	// 创建SPDP消息
	msg := messages.NewMessage(p.GUIDPrefix)

	// 添加InfoDestination子消息
	destSubmsg := &messages.InfoDestination{
		Header: messages.SubmessageHeader{
			SubmessageID: common.MessageTypeInfoDestination,
			Flags:        0x01, // 多播标志
		},
		GUIDPrefix: [12]byte{}, // 空GUID前缀表示多播
	}
	msg.AddSubmessage(destSubmsg)

	// 添加Data子消息（包含参与者信息）
	dataSubmsg := &messages.Data{
		Header: messages.SubmessageHeader{
			SubmessageID: common.MessageTypeData,
			Flags:        0x01, // 关键数据标志
		},
		ReaderID: messages.EntityID{
			EntityKey:  [3]byte{0x00, 0x00, 0x01}, // SPDP内置Reader
			EntityKind: 0xC2,                      // 内置实体
		},
		WriterID: messages.EntityID{
			EntityKey:  [3]byte{0x00, 0x00, 0x02}, // SPDP内置Writer
			EntityKind: 0xC2,                      // 内置实体
		},
		WriterSN: messages.SequenceNumber{
			High: 0,
			Low:  1,
		},
		SerializedData: p.serializeParticipantData(),
	}
	msg.AddSubmessage(dataSubmsg)

	// 发送多播消息
	return p.Transport.SendMulticastMessage(msg)
}

// 序列化参与者数据
func (p *Participant) serializeParticipantData() []byte {
	data := make([]byte, 20) // 参与者数据固定大小

	// 写入域ID
	binary.BigEndian.PutUint32(data[0:4], p.DomainID)

	// 写入协议版本
	data[4] = common.ProtocolVersionMajor
	data[5] = common.ProtocolVersionMinor

	// 写入Vendor ID
	binary.BigEndian.PutUint16(data[6:8], common.VendorIDUnknown)

	// 写入GUID前缀
	copy(data[8:20], p.GUIDPrefix[:])

	return data
}

// 接收发现消息
func (p *Participant) receiveDiscoveryMessages() {
	for {
		msg, addr, err := p.Transport.ReceiveMulticastMessage()
		if err != nil {
			fmt.Printf("Failed to receive discovery message: %v\n", err)
			continue
		}

		// 处理SPDP消息
		p.handleSPDPMessage(msg, addr)
	}
}

// 处理SPDP消息
func (p *Participant) handleSPDPMessage(msg *messages.Message, addr *net.UDPAddr) {
	// 验证消息头
	if err := msg.Header.Validate(); err != nil {
		fmt.Printf("Invalid SPDP message header: %v\n", err)
		return
	}

	// 跳过自己的消息
	if string(msg.Header.GUIDPrefix[:]) == string(p.GUIDPrefix[:]) {
		return
	}

	// 处理子消息
	for _, submsg := range msg.Submessages {
		switch sm := submsg.(type) {
		case *messages.Data:
			if sm.ReaderID.EntityKind == 0xC2 && sm.WriterID.EntityKind == 0xC2 {
				// 这是SPDP数据消息
				p.handleParticipantData(sm, addr)
			}
		}
	}
}

// 处理参与者数据
func (p *Participant) handleParticipantData(data *messages.Data, addr *net.UDPAddr) {
	if len(data.SerializedData) < 20 {
		fmt.Printf("Invalid participant data length: %d\n", len(data.SerializedData))
		return
	}

	// 解析参与者数据
	domainID := binary.BigEndian.Uint32(data.SerializedData[0:4])

	// 检查域ID是否匹配
	if domainID != p.DomainID {
		return
	}

	// 提取GUID前缀
	var guidPrefix [12]byte
	copy(guidPrefix[:], data.SerializedData[8:20])

	// 创建发现的参与者信息
	discovered := &DiscoveredParticipant{
		GUIDPrefix: guidPrefix,
		Locator: common.Locator{
			Kind:    1, // UDPv4
			Port:    uint32(addr.Port),
			Address: ipToBytes(addr.IP),
		},
		Timestamp: time.Now(),
	}

	// 添加到发现列表
	guidStr := fmt.Sprintf("%x", guidPrefix)
	p.Discovered[guidStr] = discovered

	fmt.Printf("Discovered participant: %s at %s\n", guidStr, addr.String())
}

// IP地址转换为字节数组
func ipToBytes(ip net.IP) [16]byte {
	var result [16]byte
	ipv4 := ip.To4()
	if ipv4 != nil {
		// IPv4地址
		copy(result[12:16], ipv4)
	} else {
		// IPv6地址
		copy(result[:], ip)
	}
	return result
}

// 停止参与者发现
func (p *Participant) StopDiscovery() error {
	return p.Transport.Close()
}

// 获取发现的参与者列表
func (p *Participant) GetDiscoveredParticipants() []*DiscoveredParticipant {
	result := make([]*DiscoveredParticipant, 0, len(p.Discovered))

	for _, participant := range p.Discovered {
		// 检查是否过期（超过60秒未更新）
		if time.Since(participant.Timestamp) > 60*time.Second {
			delete(p.Discovered, fmt.Sprintf("%x", participant.GUIDPrefix))
			continue
		}
		result = append(result, participant)
	}

	return result
}
